#ifndef _MAINMESSAGE_HPP_
#define _MAINMESSAGE_HPP_

#include "jhdefs.hpp"
#include "net/MediaType.hpp"
#include "net/MessageHeader.hpp"
#include "net/MailRecipient.hpp"
#include "net/PartSource.hpp"
#include "net/PartStore.hpp"
#include "net/PartHandler.hpp"
#include "net/MultipartWriter.hpp"
#include "net/MultipartReader.hpp"
#include "stdlib/timestamp.hpp"
using JHCPP::stdlib::CTimeStamp;
#include <vector>
#include <string>

NET_NAMESPACE_BEGIN

class CMailMessage : public CMessageHeader
{
public:
	typedef std::vector<CMailRecipient> Recipients;

	enum ContentDisposition
	{
		CONTENT_INLINE,
		CONTENT_ATTACHMENT
	};

	enum ContentTransferEncoding
	{
		ENCODING_7BIT,
		ENCODING_8BIT,
		ENCODING_QUOTED_PRINTABLE,
		ENCODING_BASE64
	};

	struct Part
	{
		std::string             name;
		CPartSource*            pSource;
		ContentDisposition      disposition;
		ContentTransferEncoding encoding;
	};

	typedef std::vector<Part> PartVec;

	CMailMessage(CPartStoreFactory* pStoreFactory = 0);
	virtual ~CMailMessage();

	void addRecipient(const CMailRecipient& recipient);
	void setRecipients(const Recipients& recipient);
	const Recipients& recipients() const;
	
	void setSubject(const std::string& subject);
	const std::string& getSubject() const;

	void setSender(const std::string& sender);
	const std::string& getSender() const;

	void setContent(const std::string& content, ContentTransferEncoding encoding = ENCODING_QUOTED_PRINTABLE);
	const std::string& getContent() const;

	void setContentType(const std::string& mediaType);
	void setContentType(const CMediaType& mediaType);
	const std::string& getContentType() const;

	void setDate(const CTimeStamp& dateTime);
	CTimeStamp getDate() const;

	bool isMultipart() const;

	void addPart(const std::string& name,
		CPartSource* pSource,
		ContentDisposition disposition,
		ContentTransferEncoding encoding); 
	void addContent(CPartSource* pSource,
		ContentTransferEncoding encoding = ENCODING_QUOTED_PRINTABLE);
	void addAttachment(const std::string& name,
		CPartSource* pSource,
		ContentTransferEncoding encoding = ENCODING_BASE64);

	CPartSource* createPartStore(const std::string& content,
		const std::string& mediaType,
		const std::string& filename = "");

	const PartVec& parts() const;
	
	void read(std::istream& istr, CPartHandler& handler);
	void read(std::istream& istr);
	void write(std::ostream& ostr) const;

	static std::string encodeWord(const std::string& text, const std::string& charset = "UTF-8");
	static const std::string HEADER_SUBJECT;
	static const std::string HEADER_FROM;
	static const std::string HEADER_TO;
	static const std::string HEADER_CC;
	static const std::string HEADER_BCC;
	static const std::string HEADER_DATE;
	static const std::string HEADER_CONTENT_TYPE;
	static const std::string HEADER_CONTENT_TRANSFER_ENCODING;
	static const std::string HEADER_CONTENT_DISPOSITION;
	static const std::string HEADER_CONTENT_ID;
	static const std::string HEADER_MIME_VERSION;
	static const std::string EMPTY_HEADER;
	static const std::string TEXT_PLAIN;
	static const std::string CTE_7BIT;
	static const std::string CTE_8BIT;
	static const std::string CTE_QUOTED_PRINTABLE;
	static const std::string CTE_BASE64;

protected:

	void makeMultipart();
	void writeHeader(const CMessageHeader& header, std::ostream& ostr) const;
	void writeMultipart(CMessageHeader& header, std::ostream& ostr) const;
	void writePart(CMultipartWriter& writer, const Part& part) const;
	void writeEncoded(std::istream& istr, std::ostream& ostr, ContentTransferEncoding encoding) const;
	void setRecipientHeaders(CMessageHeader& headers) const;
	void readHeader(std::istream& istr);
	void readMultipart(std::istream& istr, CPartHandler& handler);
	void readPart(std::istream& istr, const CMessageHeader& header, CPartHandler& handler);
	void handlePart(std::istream& istr, const CMessageHeader& header, CPartHandler& handler);
	static const std::string& contentTransferEncodingToString(ContentTransferEncoding encoding);
	static int lineLength(const std::string& str);
	static void appendRecipient(const CMailRecipient& recipient, std::string& str);

private:
	CMailMessage(const CMailMessage&);
	CMailMessage& operator = (const CMailMessage&);

	Recipients              m_recipients;
	PartVec                 m_parts;
	std::string             m_content;
	ContentTransferEncoding m_encoding;
	mutable std::string     m_boundary;
	CPartStoreFactory*      m_pStoreFactory;
};


NET_NAMESPACE_END

#endif
